<?php

namespace Henan\ThinkSdk\service;


use Exception;
use Henan\ThinkSdk\helper\FC;
use think\db\BaseQuery;
use think\facade\Db;
use think\facade\Request;

/**
 * 日志服务类
 * @author henan
 */
class LogService
{
    /**
     * 当前实例
     * @var
     */
    protected static $instance;

    /**
     * 连接数据库配置名称
     * @var
     */
    protected string $connect;

    /**
     * 表前缀
     * @var string
     */
    protected string $tablePrefix = '';

    /**
     * 表名称
     * @var string
     */
    protected string $tableName;

    /**
     * 表后缀
     * @var string
     */
    protected string $tableSuffix;

    /**
     * 完整表名
     * @var string
     */
    protected string $fullTableName;

    /**
     * 响应内容
     * @var mixed|null
     */
    protected mixed $response = null;

    /**
     * 获取实例对象
     * @param string $connect 连接数据库配置名称
     * @param string $tableName 表名称
     * @param string $tablePrefix 表前缀
     * @return LogService
     */
    public static function instance(string $connect, string $tableName, string $tablePrefix = ''): LogService
    {
        if (is_null(self::$instance)) self::$instance = new static($connect, $tableName, $tablePrefix);
        return self::$instance;
    }

    /**
     * 构造方法
     * @param string $connect 连接数据库配置名称
     * @param string $tableName 表名称
     * @param string $tablePrefix 表前缀
     */
    protected function __construct(string $connect, string $tableName, string $tablePrefix = '')
    {
        $this->connect = $connect;
        $this->tableName = $tableName;
        $tablePrefix && $this->tablePrefix = $tablePrefix;
        $this->tableSuffix = date('Ym', time());
        $this->fullTableName = "{$this->tablePrefix}{$this->tableName}_{$this->tableSuffix}";
        return $this;
    }

    /**
     * 设置响应对象
     * @param $response
     * @return LogService
     */
    public function response($response): LogService
    {
        $this->response = $response;
        return $this;
    }

    /**
     * 获取数据表对象
     * @param string $tableSuffix 表后缀
     * @return BaseQuery
     */
    public function getModel(string $tableSuffix): BaseQuery
    {
        empty($tableSuffix) && $tableSuffix = date('Ym', time());
        return Db::connect($this->connect)->table("{$this->tablePrefix}{$this->tableName}_{$tableSuffix}");
    }

    /**
     * 保存数据
     * @param array $data
     * @return void
     * @throws Exception
     */
    public function save(array $data = []): void
    {
        Db::startTrans();
        try {
            $this->detectTable();
            $data['url'] = FC::getUrl();
            $data['method'] = Request::method();
            $data['param'] = json_encode(Request::param(), 320);
            $data['ip'] = Request::ip();
            $data['useragent'] = $_SERVER['HTTP_USER_AGENT'] ?? null;
            $data['create_time'] = date('Y-m-d H:i:s');
            $this->response && $data['response'] = json_encode($this->response->getData(), 320);
            Db::connect($this->connect)->table($this->fullTableName)->insert($data);;
            Db::commit();
        } catch (Exception $e) {
            Db::rollback();
            throw new Exception($e->getMessage());
        }
    }

    /**
     * 检测数据表
     * @return void
     */
    protected function detectTable(): void
    {
        $check = Db::connect($this->connect)->query("show tables like '{$this->fullTableName}'");
        if (empty($check)) $this->CreateTable();
    }

    /**
     * 创建表
     * @return void
     */
    protected function CreateTable(): void
    {
        $sql = <<<EOT
CREATE TABLE `{$this->fullTableName}` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '日志id',
  `url` varchar(225) COMMENT '请求地址',
  `method` varchar(12) COMMENT '请求方法',
  `param` longtext COMMENT '请求参数(json)',
  `response` longtext COMMENT '响应内容(json)',
  `title` varchar(125)  COMMENT '日志标题',
  `content` text  COMMENT '日志内容',
  `app` varchar(32)  COMMENT '应用',
  `uid` int(11)  COMMENT '账号id',
  `role` varchar(32)  COMMENT '账号角色',
  `ip` varchar(32) COMMENT 'IP',
  `useragent` varchar(255) COMMENT 'User-Agent',
  `create_time` datetime  COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='日志表 - {$this->fullTableName}';
EOT;
        Db::connect($this->connect)->execute($sql);
    }
}